package Recomendadores;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Iterator;

import UserProfile.Calificacion;
import UserProfile.Configuration;
import UserProfile.NoExisteLaOntologiaException;
import UserProfile.NoSePudoPersistirElModeloException;
import UserProfile.UserDataFileReader;
import UserProfile.UserOntologyManager;


public class RecomendadorPorContenido {

	public static void recomendadorPorContenido(){
		Configuration conf = Configuration.getInstance();

		//creo el archivo de salida			
		try {
			FileWriter f1 = new FileWriter(conf.getOUTCONTENT());			
			BufferedWriter b1 = new BufferedWriter(f1);

			ArrayList<ArrayList<Calificacion>> agrupados = UserDataFileReader.RatingsReadLines(conf.getDBTEST());

			Iterator<ArrayList<Calificacion>> ite = agrupados.iterator();
			while(ite.hasNext()){
				ArrayList<Calificacion> grupo = ite.next();
				if(grupo.isEmpty()) continue;
				int idUser = grupo.get(0).getIdUser();
				ArrayList<Movie> historia = UserOntologyManager.getMoviesByUser(UserOntologyManager.getUserModel(idUser,conf), conf);					
				Iterator<Calificacion> ite2 = grupo.iterator();
				if(historia.size()>0){
					while(ite2.hasNext()){
						Calificacion cal = ite2.next();
						Movie moviePorPredecir = UserOntologyManager.getMovieModel(cal.getIdMovie(),Math.round((float)cal.getRating()),cal.getIdUser(),historia.get(0).getOrden(), conf); //obtengo el modelo Movie de la moviePorPredecir
						if(moviePorPredecir!=null){
							historia.add(0, moviePorPredecir); //agrego la moviePorPredecir en el primer lugar del arrayList
							double predictedDoi = RecomendadorPorContenido.recomendar(historia);//obtener recomendaciones

							String linea =  cal.getIdUser()+","+cal.getIdMovie()+","+predictedDoi+","+cal.getRating();
                                                        System.out.println(linea+"\nel error es: "+Math.abs(predictedDoi-cal.getRating()));
														
                                                       //guardo el predited doi en el archivo de salida						    
							b1.write(linea);
							b1.newLine();
							b1.flush();
						}							
					}
				}
			}
			b1.close();
		} catch (NoExisteLaOntologiaException | NoSePudoPersistirElModeloException e) {
			e.printStackTrace();
		} catch (Exception e1) {
			e1.printStackTrace();
		}

	}

	//Metodo para calcular similitud del coseno entre vectores
	public static double recomendar (ArrayList<Movie> peliculas){



		double[] similitud = new double [peliculas.size()-1];
		double[] doi = new double [peliculas.size()];

		similitudDelCoseno(peliculas, similitud, doi);

		int count = 0;
		for(int i=0;i<similitud.length;i++){
			if(similitud[i]!=0) count++;
		}

		return predecirDOI(count, similitud, doi);


	}

	//Metdo para calcular similitud entre peliculas
	public static void similitudDelCoseno (ArrayList<Movie> peliculas, double[] similitud, double[] doi){

		//La primer pelicula del ArrayList peliculas es la pelicula de la cual quiero predecir el DOI
		Movie peliculaSinDOI = peliculas.get(0);
		float [] generosSinDOI = peliculaSinDOI.getGeneros();
		doi[0] = peliculaSinDOI.getDoi();

		for(int i=1; i<peliculas.size(); i++){
			Movie auxiliar = peliculas.get(i);
			float [] generos = auxiliar.getGeneros();
			doi[i] = auxiliar.getDoi();

			double norma1=0;
			double norma2=0;
			float productoEscalar = 0;

			for(int j=0; j<generos.length; j++){
				productoEscalar = productoEscalar + (generos[j]*generosSinDOI[j]);
				norma1 = norma1 + (Math.pow(generosSinDOI[j], 2));
				norma2 = norma2 + (Math.pow(generos[j], 2));
			}

			norma1 = Math.sqrt(norma1);
			norma2 = Math.sqrt(norma2);
			similitud[i-1] = productoEscalar/(norma1*norma2);
		}
	}

	//Metodo para calcular DOI
	public static double predecirDOI(int cantPeliculas,double[] similitud, double[] doi){
		double resultado = 0;
		for(int i=0; i<similitud.length; i++){
			similitud[i] = similitud[i]*doi[i];
			resultado = resultado + similitud[i];

		}

		resultado = resultado/cantPeliculas ;
		return resultado;

	}
	
	public static void main(String[] args) {
		RecomendadorPorContenido.recomendadorPorContenido();

	}

}
